﻿#ifndef JZCO_CO_COROUTINE_H_
#define JZCO_CO_COROUTINE_H_

#include <QObject>
#include <QThread>
#include <functional>
#include <QSharedPointer>
#include <QException>
#include "JZCoContext.h"

class JZCoScheduler;
class JZCoInterrupt : public QException
{
public:
};

/*
注意：协程依赖主线程调度，主线程不能阻塞
     协程中最好不要执行事件循环和信号响应，有调度风险
*/
class JZCoCoroutine
{
public:
    explicit JZCoCoroutine();
    virtual ~JZCoCoroutine();

    void setTask(const std::function<void()>& func);
    void run();

    void quit();
    bool isInterrupt() const;
    bool isFinish() const;

protected:
    friend JZCoScheduler;

    virtual void beforeYield();
    virtual void beforeResume();
    virtual void endTask();

    bool m_interrupt;
    bool m_finish;
    JZCoContext* m_ctx;
    QList<JZCoCoroutine*> m_preCoList;
    std::function<void()> m_func;
};
typedef QSharedPointer<JZCoCoroutine> JZCoCoroutinePtr;

class JZCoThread : public QThread 
{
public:
    JZCoThread(std::function<void()> func);

    virtual void run();

protected:
    std::function<void()> m_func;
};

class JZCoScheduler : public QObject
{
    Q_OBJECT

public:
    static JZCoScheduler* instance();

    JZCoScheduler();
    ~JZCoScheduler();
    
    void init();
    bool isInCoroutine();

    JZCoMainContext* mainContext();
    JZCoCoroutine *currentCoroutine();
    void yield(JZCoCoroutine *co);
    void resume(JZCoCoroutine *co);

    void startTask(JZCoCoroutinePtr task);
    void endTask(JZCoCoroutine *task);

protected slots:
    void onClearContext();

protected:
    QList<JZCoCoroutinePtr> m_coList;
    QList<JZCoContext*> m_finished;
    JZCoMainContext* m_mainCtx;
    JZCoCoroutine* m_co;
};
#define g_scheduler JZCoScheduler::instance()

#endif // !JZCO_NET_WORK_H
